<template>
    <a-skeleton :animation="true" :class="[{ 'height': !chatDetail?.app }]" :style="{ 'padding-top': `${customInfoHeight}px` }" @click="handleBtn('read')">
        <div :class="['right-chat']">
            <!-- 群聊列表 -->
            <div :class="['chat', { 'height': chatDetail?.status === 1 || !isChat }]" ref="chatRef" :style="{ height: `calc(100% - ${sendIptHeight}px)` }" @scroll="onScroll">
                <a-skeleton-line :rows="1" :line-height="500" v-if="!chatDetail?.id"/>
                <template v-else>
                    <div v-for="(item, itemIndex) in chatList" :key="item.id" :class="['item', { 'item-self': item.isSelf }, { 'item-at': item.isHistory }]" :ref="(el) => setItemRef(el, item.id)">
                        <div class="time history" v-if="item.isHistory">
                            <span>以上是历史消息</span>
                        </div>
                        <div class="time" v-if="shouldShowTime(itemIndex)">{{ formatChatTime(item.sendTime, true) }}</div>
                        <div :class="['box', {'box-style': item.btnType || useWebsocketStore().chatType.includes(item.type)}]">
                            <template v-if="item.btnType || useWebsocketStore().chatType.includes(item.type)">
                                <div class="tips">{{ item.btnTips || item.content }}</div>
                            </template>
                            <template v-else>
                                <ComAvatar :sex="item.sex" :name="item.initialLetter" :size="32"/>
                                <div class="info">
                                    <div class="name">
                                        <div :class="['name-box', { 'style': item.isSelf }]">
                                            {{ item.sendName || '-' }}
                                            <span class="creator" v-if="item.sendId === chatDetail?.creatorId">召集人</span>
                                            <span class="email" v-if="item.sendId !== userInfo.id">
                                                <a :href="'mailto:' + userList.find(child => child.id === item.sendId)?.email" class="email-link">
                                                    {{ userList.find(child => child.id === item.sendId)?.email }}
                                                </a>
                                            </span>
                                        </div>
                                    </div>
                                    <!-- 文字、图片、表情包等等 -->
                                    <div class="msg" v-dompurify-html="item.content" @click="handleBtn('preview', $event)" v-if="item.content"></div>
                                    <!-- 文档类型 -->
                                    <template v-else>
                                        <!-- 图片 -->
                                        <!-- <div class="card img" v-if="item.type === 1">
                                            <img :src="`${FILE_PREVIEW}/${item.extraInfo?.url}`" alt="" @click="handleBtn('preview', $event)">
                                        </div> -->
                                        <!-- 文档 -->
                                        <div class="card file" v-if="[1, 2,4].includes(item?.type)" @click="handleBtn('downVisible', {...item.extraInfo, type: item.type})">
                                            <div class="left">
                                                <div class="name">
                                                    <div>{{ getFileName(item.extraInfo?.originalFilename) }}</div>
                                                    <span>{{ `.${item.extraInfo?.ext }` }}</span>
                                                </div>
                                                <div class="size">{{ getFileUnit(item.extraInfo?.size) }}</div>
                                            </div>
                                            <img src="@/assets/icon-file.svg" alt="" class="EachApp">
                                        </div>
                                        <!-- 语音 -->
                                        <div class="card voice" v-if="item?.type === 3">语音</div>
                                    </template>
                                </div>
                            </template>
                        </div>
                    </div>
                </template>
                <i class="EachApp EachApp_fanhuidibu back-bottom flex" :style="{ bottom: `${sendIptHeight + 30}px` }"
                    @click="isBottom = false; chatRef?.scrollTo({ top: chatRef.scrollHeight, behavior: 'smooth' });" v-if="isBottom"></i>
            </div>
            <!-- 群聊有人@我 -->
            <Aite v-if="isAt" ref="atRef" @handleAite="handleBtn('handleAite', $event)" :chatList="chatList" :chatRef="chatRef" :itemRefs="itemRefs" :positionId="positionId" :sendIptHeight="sendIptHeight"></Aite>
            <!-- 群聊输入框 -->
            <template v-if="isChat">
                <div class="ipt" id="ipt">
                    <a-skeleton-line :rows="1" :line-height="129" v-if="!chatDetail?.id"/>
                    <div class="ipt-box" @click="handleClickInput" v-else>
                        <!-- 选择成员弹窗 -->
                        <div class="users" id="users" v-if="isChoose" :style="{
                            bottom: isChooseTop + 'px',
                            left: isChooseLeft + 'px',
                        }">
                            <div v-for="(item, index) in chatUserList" :key="item.id" :class="['item', { 'item-style': chatUserIndex === index }]"
                            @click="handleBtn('chooseUser', item)" @mouseenter="chatUserIndex = index">
                                <ComAvatar :sex="item.sex" :name="item.initialLetter" :size="24"/>
                                <span class="name">{{ item.name }}</span>
                            </div>
                        </div>
                        <!-- 文本输入框 -->
                        <div ref="myTextareaRef" :class="['sendIpt', { 'no-tips': myTextareaRef?.innerHTML }, { 'placeholder': !isSend }]" contenteditable="true"
                            @paste.prevent="onPaste" @keydown="handleDown" @input="handleInput" @blur="onBlur" @click="saveCursorPosition">
                        </div>
                        <div class="space"></div>
                        <!-- 工具栏 -->
                        <div class="tools">
                            <Tools @toolsEmit="toolsEmit" :isSend="isSend"/>
                        </div>
                        <div class="clear-both"></div>
                    </div>
                </div>
            </template>
        </div>
    </a-skeleton>
    <!-- 预览 -->
    <a-image-preview-group
        v-model:visible="previewVisible"
        v-model:current="previewIndex"
        :srcList="previewList"
        infinite
    />
    <!-- 下载弹窗 -->
    <a-modal v-model:visible="modalVisible" modal-class="down-modal" :render-to-body="false" width="460px" @ok="modalVisible = true" :closable="false">
        <template #title>下载文件</template>
        <div>{{ getFileName(downLoadFileMsg.originalFilename) }}({{ getFileUnit(downLoadFileMsg?.size) }})</div>
        <template #footer>
            <a-button @click="modalVisible = false">取消</a-button>
            <a-button @click="handleBtn('downLoad')" class="submit">确定</a-button>
        </template>
    </a-modal>
</template>
<script lang="ts" setup>
import type { UserInfoEntity } from '@/entity/UserEntity';
import type { chatListEntity, chatDetailEntity, currentGroupInfoEntity, SendParamsEntity } from '@/entity/im/ImEntity';
defineProps<{
    userList: UserInfoEntity[];
}>()
import ComAvatar from '@/components/ComAvatar.vue';
import { debounce } from 'lodash-es';
import Tools from './Tools.vue';
import * as Api from '@/api/im';
import mitt from "@/utils/bus";
import Aite from './Aite.vue';
import {formatChatTime, getFileUnit, fileToBlob} from '@/utils/index';
import {insertImageAtCursor, resizeImageDimensions} from '@/utils/img';
import mixin from "@/mixins/index";
import { FILE_PREVIEW } from '@/enums/appEnum';
import { useUserStore } from '@/stores/modules/user';
import useEmitter from '@/hooks/useEmitter.ts';

const userInfo = reactive({
	id: useUserStore().userInfo?.id
});
import { useWebsocketStore } from '@/stores/modules/websocket';
const { imStore } = useWebsocketStore();
import { getFileName } from '@/utils/index';
const emit = defineEmits(['handlePreNext', 'inputVal']);
const injectNotification = inject('handleNotification');
const { handleMixinSubmit } = mixin();
const route = useRoute();
const isCollapse = ref<boolean>(false);
const sendIptHeight = ref<number | undefined>(0); // 发送框高度
const chatList = ref<chatListEntity[]>([]); // 消息列表
const chatDetail = ref<chatDetailEntity>({
    userIds: [],
}); // 消息详情
const modalVisible = ref(false);
const chatRef = ref<HTMLDivElement | null | any>(null);
const chatInfo = ref<chatListEntity>({
    isPreLast: false,
    isNextLast: true
}); // 分页信息
const sendParams = ref<SendParamsEntity>({
	content: '',
	extraInfo: {
		ext: '',
		fileName: '',
		id: '',
		originalFilename: '',
		size: 0,
		url: '',
	},
	mentionedIds: [],
	topicId: 0,
	type: 0
})
const isSend = ref<boolean>(false); // 是否可以发送文本
const myTextareaRef = ref<HTMLTextAreaElement | null>(null);
const currentGroupInfo = ref<currentGroupInfoEntity>({}); // 当前群聊信息
const isChat = ref<boolean>(true); // 是否可发送消息
const currentInsertIndex = ref<string>(''); // 当前输入框index下标位置
const previewVisible = ref<boolean>(false);
const previewList = ref<string[]>([]); // 预览列表
const previewIndex = ref<number>(0); // 预览下标
const isBottom = ref(false); // 是否到底
const customInfoHeight = ref<number>(0); // 客户信息区域的高度
const blurRange = ref<Range | null>(null);
const atSearchText = ref<string>('');

// 定位相关信息
const isAt = ref(false); // 是否有@
const isChoose = ref(false); // 是否选择成员(@)
const isChooseTop = ref(0); // 选择框上距离
const isChooseLeft = ref(0); // 选择左距离
const chatUserIndex = ref(-1); // 选择用户下标
const chatUserList = ref<UserInfoEntity[]>([]); // 群聊成员列表
const atRef = ref<HTMLInputElement | null>(null);
// 1843900232112
const positionId = ref<number | string>(''); // 定位id
const itemRefs = ref({});
const lastScrollTop = ref(0); // 存储上一次的滚动位置
const scrollDirection = ref(''); // 滚动方向
onBeforeUpdate(() => {
  itemRefs.value = {}
})
const setItemRef = (el: any, id: number) => {
    if (el) itemRefs.value[id] = el
}

watch(() => isAt.value, e => {
    if(!e){
        // 重置定位id
        positionId.value = '';
    }
})

onMounted(() => {
    window.addEventListener('storage', handleAddEventListener);
    window.addEventListener('click', handleClickOutside);
})

onUnmounted(() => {
    window.removeEventListener('storage', handleAddEventListener);
    window.removeEventListener('click', handleClickOutside);
    mitt.off('handleSubmit', mittHandleSubmit);
    mitt.off('handleCollapse', mittHandleCollapse);
    mitt.off('customInfoHeight', mittCustomInfoHeight);
    mitt.off('handleChatBtn', mittHandleChatBtn);
})

// 收到的消息-处理
const handleAddEventListener = (event: any) => {
    const websocketMsg = event.target.localStorage.websocketMsg;
    if(websocketMsg){
        const newValue = JSON.parse(websocketMsg);
        const data = JSON.parse(newValue?.v);
        handleOnMessage(data);
    }
}

// 收到的消息-处理
const handleOnMessage = debounce((params, isStore = false) => {
    // 处理群聊消息等正常消息
    const { id, sendId, sendTime, content, topicId, type, sendType, extraInfo, mentionedIds } = params;
    console.log('ws收到消息===function:', sendType, {...params});
    const sendName = imStore.userList.find(child => child.id === sendId)?.nickname;
    // 我自己
    const isMyself = userInfo.id === sendId;
    injectNotification({ content, sendName });
    // 处理如果当前正处于群聊消息界面，则直接监听该@消息是否处于浏览器可视区域
    if(mentionedIds?.length && currentGroupInfo.value.id === topicId){
        isAt.value = !isMyself;
        positionId.value = positionId.value ? positionId.value : id;
    }
    atRef.value?.handleNewData(positionId.value);
    // SYSTEM_MESSAGE系统消息   GROUP_MESSAGE会话消息
    if(sendType === 'GROUP_MESSAGE'){
        let contentNew = content;
        if(extraInfo?.url){
            previewList.value.push((`${FILE_PREVIEW}/${extraInfo?.url}`).replace('.png_thumb', ''));
        }
        if(contentNew?.includes('<img')){
            contentNew = contentNew?.replace(/src="([^"]*)"/g, (_match: any, p1: string|string[]) => {
                const isHave = p1.includes('preview');
                const url = `${isHave ? '' : `${FILE_PREVIEW}/`}${p1}`;
                previewList.value.push(url.replace('.png_thumb', ''));
                return `src="${url}"`;
            });
        }
        mitt.emit('sendMsg', { sendType, sendName, ...params, mentionedIds: isMyself ? [] : mentionedIds });
        // 是否当前处于接收消息的群里(true: push新信息， 反之则no)
        const isNewMsgGroup = chatDetail.value.id === topicId;
        if(isMyself){
            if(!(useWebsocketStore().chatType.includes(type))){
                chatList.value.push({
                    id,
                    type,
                    sex: imStore.userList.find(child => child.id === userInfo.id)?.sex,
                    sendId: userInfo.id,
                    sendName: imStore.userList.find(child => child.id === userInfo.id)?.nickname,
                    sendTime,
                    initialLetter: imStore.userList.find(child => child.id === userInfo.id)?.initialLetter,
                    content: contentNew,
                    extraInfo,
                    isSelf: true
                })
            }
        }else{ // 当前人发送消息不加，其他人+1
            if(type !== 32){
                if(currentGroupInfo.value.id === topicId){
                    currentGroupInfo.value.unread += 1;
                }
            }
        }
        // 如果登录人和发送消息的人不是同一个人1
        if(!isMyself && isNewMsgGroup){
            // 删除、归档不Push消息
            if(!(useWebsocketStore().chatType.includes(type))){
                chatList.value.push({
                    id,
                    type,
                    sendId,
                    sendName,
                    sendTime,
                    sex: imStore.userList.find(child => child.id === sendId)?.sex,
                    initialLetter: imStore.userList.find(child => child.id === sendId)?.initialLetter,
                    content: contentNew,
                    extraInfo,
                })
            }
        }
        // 添加文字提示
        if(chatDetail.value.id === topicId && [21, 31].includes(type)){
            chatList.value.push({ ...params, sendTime });
        }
    }else if(sendType === 'SYSTEM_MESSAGE'){ // 系统消息
        mitt.emit('sendMsg', { sendType,  ...params});
    }
    handleChatBottom();
}, route.path === '/im' ? 0 : 100);

// 点击外部区域，则选择框消失
const handleClickOutside = (event: any) => {
    const usersElement = document.getElementById('users');
    if (usersElement && !usersElement.contains(event.target) && event.target.tagName !== 'I') {
        isChoose.value = false;
    }
};

// 消息详情
const getChatDetail = async (topicId: number, isEmpty = false) => {
    try{
        const res = await Api.ApiChatListDetail(topicId);
        chatDetail.value = res;
        customInfoHeight.value = 0;
        getChatUserList(topicId);
        await getRecordList(topicId, isEmpty);
		useEmitter.emit('chatDetail', chatDetail.value);
        const timer = setTimeout(() => {
            clearTimeout(timer);
            if(myTextareaRef.value){
                myTextareaRef.value.textContent = '';
                myTextareaRef.value.focus();
                saveCursorPosition();
                isSend.value = false;
            }
        }, 100);
    }catch(err){console.log(err);}
}
// 获取群聊用户成员
const getChatUserList = async (topicId: number) => {
    try{
        const res = await Api.ApiChatListDetailUser(topicId);
        const arr = res?.filter((item: chatDetailEntity) => !item.isQuit) || [];
        chatDetail.value.users = arr;
        chatDetail.value.userIds = arr?.map((item: chatDetailEntity) => item.id);
        chatDetail.value.creatorId = arr?.find((item: chatDetailEntity) => item.isCreator)?.id;
        const params = {
            id: 0,
            name: '所有人',
            initialLetter: 'All'
        }
        chatUserList.value = [params, ...arr].filter(item => item.id !== userInfo.id);
    }catch(err){console.log(err);}
}

// 消息列表
const getRecordList = async (topicId: number, isEmpty: boolean) => {
    if(isEmpty){
        chatList.value = [];
    }
    // chatInfo.value.isPreLast = true;
    try{
        let params = { nextId: chatInfo.value.nextId };
        const isUp = scrollDirection.value === 'up'; // 是否往上滚动
        if(isUp){
            params = { preId: chatInfo.value.preId };
        }
        const res = await Api.ApiChatListRecord(topicId, params);
        if(isUp){
            chatList.value = [...res?.data?.reverse() || [], ...chatList.value];
            const container = chatRef.value;
            // 记录当前滚动位置和高度
            const prevScrollHeight = container.scrollHeight;
            const prevScrollTop = container.scrollTop;
            // 数据加载完成后调整滚动位置
            nextTick(() => {
                const newScrollHeight = chatRef.value.scrollHeight;
                container.scrollTop = prevScrollTop + (newScrollHeight - prevScrollHeight);
            });
        }else{
            chatList.value = [...chatList.value,...res?.data.reverse() || []];
        }
        chatInfo.value = {
            ...res,
            isPreLast: res?.isPreLast || chatInfo.value.isPreLast,
            isNextLast: res?.isNextLast || chatInfo.value.isNextLast,
            nextId: res?.nextId || chatInfo.value.nextId,
            preId: res?.preId || chatInfo.value.preId,
        };

        if(chatList.value.length > 0){
            chatList.value.map(item => {
                item.sex = imStore.userList.find(child => child.id === item.sendId)?.sex;
                item.sendName = imStore.userList.find(child => child.id === item.sendId)?.nickname;
                item.initialLetter = imStore.userList.find(child => child.id === item.sendId)?.initialLetter;
                item.isSelf = item.sendId === userInfo.id;
                if(item.content?.includes('<img')){
                    item.content = item.content.replace(/src="([^"]*)"/g, (match, p1) => {
                        return `src="${item.content.includes(FILE_PREVIEW) ? '' : `${FILE_PREVIEW}/`}${p1}"`;
                    });
                }
                return item;
            })
            const imgLinks: string[] = [];
            chatList.value.forEach(item => {
                const parser = new DOMParser();
                const doc = parser.parseFromString(item.content, 'text/html');
                const imgs = doc.querySelectorAll('img');
                imgs.forEach(img => {
                    imgLinks.push(img.getAttribute('src').replace('.png_thumb', ''));
                });
                if(item.extraInfo?.url){
                    imgLinks.push(item.extraInfo?.url.includes(FILE_PREVIEW) ? item.extraInfo?.url?.replace('.png_thumb', '') : (`${FILE_PREVIEW}/${item.extraInfo?.url}`).replace('.png_thumb', ''));
                }
            });
            previewList.value = imgLinks;
        }
        if(isBottom.value){
            // 默认直接滚动到底部
            nextTick(() => {
                myTextareaRef.value?.focus();
            });
        }
        sendIptHeight.value = document.getElementById('ipt')?.offsetHeight; // 获取容器高度去计算聊天区的高度
    }catch(err){console.log(err);}
}

// 根据定位ID获取上下文列表
const getPositionList = async () => {
    try{
        const res = await Api.ApiGetFirstAiteIdList({ topicId: currentGroupInfo.value.topicId, messageId: positionId.value });
        if(res.data?.length > 0){
            chatList.value = res.data;
            chatInfo.value = res;
            chatList.value.map(item => {
                item.isHistory = item.id === positionId.value;
                item.sex = imStore.userList.find(child => child.id === item.sendId)?.sex;
                item.sendName = imStore.userList.find(child => child.id === item.sendId)?.nickname;
                item.initialLetter = imStore.userList.find(child => child.id === item.sendId)?.initialLetter;
                item.isSelf = item.sendId === userInfo.id;
                if(item.content?.includes('<img')){
                    item.content = item.content.replace(/src="([^"]*)"/g, (match, p1) => {
                        return `src="${item.content.includes(FILE_PREVIEW) ? '' : `${FILE_PREVIEW}/`}${p1}"`;
                    });
                }
                return item;
            })
        }
        console.log('获取上下文列表===', res);
    }catch(err){console.log(err);}
}

// 查询第一条@我的消息id
const getFirstAiteId = async (topicId: number) => {
    try{
        const res = await Api.ApiGetFirstAiteId(topicId);
        positionId.value = res || null;
    }catch(err){console.log(err);}
}

// 已读群聊消息
const handleReadList = async (topicId: number, msgType: number = 0) => {
    try{
        await handleMixinSubmit(Api.ApiChatRead, topicId, '', false);
        mitt.emit('sendMsg', { sendType: 'read', topicId });
        currentGroupInfo.value.unread = 0;
		useWebsocketStore().setImCountAll();
    }catch(err){console.log(err);}
}

// 处理工具包的参数
const toolsEmit = ({ toolsType, values }: any) => {
    handleClickInput();
    if(toolsType === 'emoji'){ // 表情包
        const iptBoxDiv = document.querySelector('.sendIpt'); // 获取父容器
        // 检查 iptBoxDiv 下是否有 <div>&nbsp;</div> 标签
        if (iptBoxDiv) {
            const emptyDivs = iptBoxDiv.querySelectorAll('div'); // 获取所有 div 元素
            emptyDivs.forEach(div => {
                if (div.innerHTML === '&nbsp;') { // 判断 div 的内容是否为 &nbsp;
                    div.remove(); // 删除该 div
                }
            });
        }
        if (!currentInsertIndex.value) return;
        const emoji = values;
        const range = currentInsertIndex.value.cloneRange();

        // 插入表情
        range.deleteContents();
        const textNode = document.createTextNode(emoji);
        range.insertNode(textNode);

        // 调整光标位置到表情之后
        range.setStartAfter(textNode);
        range.setEndAfter(textNode);

        const selection = window.getSelection();
		if(selection){
			selection.removeAllRanges();
			selection.addRange(range);
		}

        // 重新获取焦点并保存新的光标位置
        myTextareaRef.value?.focus();
        saveCursorPosition();
        isSend.value = true;
    }else if(toolsType === 'file'){ // 文件上传
        sendParams.value.content = '';
        const { fileId, fileUrl, fileSize, fileName, fileType, fileExt, originalFilename } = values;
        if(fileType === 'file'){
            sendParams.value.extraInfo = {
                ext: fileExt
            }
        }else if(fileType === 'img'){
            sendParams.value.extraInfo = {
                ext: fileExt
            }
            // const w = width > 180 ? 180 : width;
            // const h = height > 180 ? 180 : height;
            // sendParams.value.content = `<p><img src=\"${fileExt === 'gif' || fileSize > size ? gifPreviewUrl : base64}\" style=\"width: ${w}px; height: ${h}px; display: block;\"></p>`;
            // handleSend(sendParams.value.content);
            // return;
        }else if(fileType === 'video'){
             sendParams.value.extraInfo = {
                ext: fileExt
                // thumbWidth: '',
                // thumbHeight: '',
                // thumbSize: '',
                // thumbUrl: '',
            }
        }
        sendParams.value.extraInfo = {id: fileId, fileName, url: fileUrl, originalFilename, size: fileSize, ...sendParams.value.extraInfo};
        handleSend(fileType);
    }else if(toolsType === 'text'){ // 文本
        const params = {
            isBtn: true,
            key: 'Enter',
            keyCode: 13,
        }
        handleDown(params);
    }else if(toolsType === '@'){ // @人员
        handleAtSymbol();
    }
}
// 点击工具栏@弹窗
const handleAtSymbol = () => {
    document.execCommand('insertText', false, '@');
    saveCursorPosition();
    isChoose.value = true;
};

// 获取当前光标位置
const saveCursorPosition = () => {
    const selection = window.getSelection();
    // console.log('selection===',);
    if (selection && selection.rangeCount > 0) {
        currentInsertIndex.value = selection.getRangeAt(0);
        // console.log('光标====', currentInsertIndex.value.startOffset);
    }
};

const handleClickInput = () => {
    // 获取输入框元素
    const sendIptElement = myTextareaRef.value;

    // 如果输入框存在
    if (sendIptElement) {
        // 聚焦到输入框
        sendIptElement.focus();

        // 如果存在上一次的光标位置
        if (currentInsertIndex.value) {
            const selection = window.getSelection();
			if(selection){
				selection.removeAllRanges();
				selection.addRange(currentInsertIndex.value);
			}
        }
    }
};
// 处理失去焦点事件
const onBlur = () => {
    const selection = window.getSelection();
    blurRange.value = selection.getRangeAt(0);
    // saveCursorPosition();
    // isChoose.value = false;
};

// 选择成员用span包裹
const handleUserToSpan = (val) => {
    // console.log('val===', {...val});
    if(val?.id >= 0){
		if(blurRange.value){
        	const currentBlurRange = blurRange.value;
			const endContainer = currentBlurRange.endContainer;
			const startOffset = endContainer.data?.indexOf("@" + atSearchText.value);
			const endOffset = startOffset + atSearchText.value?.length + 1;
			currentBlurRange.setStart(endContainer, startOffset);
			currentBlurRange.setEnd(endContainer, endOffset);
			currentBlurRange.deleteContents();
			currentBlurRange.collapse();
			myTextareaRef.value.focus();
			const element = document.createElement('SPAN');
			element.className = "chat-at-user";
			element.dataset.id = val.id;
			element.contentEditable = 'false';
			element.innerText = `@${val.name}`;
			currentBlurRange.insertNode(element);
			currentBlurRange.collapse();
			const textNode = document.createTextNode('\u00A0');
			currentBlurRange.insertNode(textNode);
			currentBlurRange.collapse();
			atSearchText.value = "";
			selectElement(textNode, 1);
			isChoose.value = false;
		}
    }

    nextTick(() => {
        const nodes = myTextareaRef.value?.childNodes;
		if(nodes){
			for (let i = 0; i < nodes.length; i++) {
				const node = nodes[i];
				const nodeName = node.nodeName.toLowerCase();
				if (nodeName === 'span') {
					const id = node.dataset.id;
					if (id) {
						sendParams.value.mentionedIds.push(+id);
					}
				}
				if(nodeName === 'div'){
					sendParams.value.mentionedIds = [];
					// 使用 querySelector 方法选择具有 chat-at-user 类的 span 元素
					const spanElements = node.querySelectorAll('span.chat-at-user');
					spanElements.forEach(span => {
						const id = span.dataset.id;
						if(id){
							sendParams.value.mentionedIds.push(+id);
						}
					});
				}
			}
		}
        sendParams.value.mentionedIds = [...new Set(sendParams.value.mentionedIds)];
    })

}
const downLoadFileMsg = ref('');
// 操作统一处理
const handleBtn = async (type: string, val: any = '') => {
    if(type === 'chooseUser'){ // @选择成员
        handleUserToSpan(val);
    }else if(type === 'preview'){ // 预览图片
        if(val.target.tagName === 'IMG'){
            const url = `${val.target.src}`;
            previewVisible.value = true;
            const parts = url.split('/');
            const fileName = parts[parts.length - 1].replace('.png_thumb', '');
            previewIndex.value = previewList.value.findIndex(item => item.includes(fileName)) || 0;
        }
    }else if(type === 'downVisible'){ // 下载弹窗
        modalVisible.value = true;
        downLoadFileMsg.value = val;
    }else if(type === 'downLoad'){ // 下载文件
        const { id, originalFilename } = downLoadFileMsg.value;
        if(id){
            await fileToBlob(id, `${originalFilename}`);
            modalVisible.value = false;
        }
    }else if(type === 'handleAite'){ // 根据定位id获取上下文
        if(!val){
            console.log('获取@上下文===', positionId.value);
            await getPositionList();
            await handleChatBottom();
            currentGroupInfo.value.hasMentioned = false;
        }
        handleReadList(chatDetail.value.id);
        isAt.value = false;
        const element = itemRefs.value[positionId.value];
        chatRef.value.scrollTo({
            top: element.offsetTop - 100,
            behavior: 'smooth'
        })
        chatList.value.map(item => {
            return item.isHistory = item.id === positionId.value;
        })
    }else if(type === 'read'){ // 点击聊天区就已读
        const { unread, topicId } = currentGroupInfo.value;
        if(unread > 0){
            handleReadList(topicId);
        }
    }
}
// 设置是否有发送内容
const setIsSend = () => {
	if(myTextareaRef.value){
		// 获取输入框的HTML内容
		const htmlContent = myTextareaRef.value.textContent;
		if(htmlContent){
			// 去除HTML标签和空格后检查内容是否为空
			const textContent = htmlContent.trim().replace('&nbsp;', '');
			// 如果有文本内容或者包含图片标签，则认为有内容
			isSend.value = textContent.length > 0 || htmlContent.includes('<img');
		}
	}
}

// 输入内容--键盘事件
const handleDown = (event: KeyboardEvent) => {
   // console.log('handleDown===', event);
   function isBtnFun(){
        if(!(event as any).isBtn){
            event.preventDefault();
        }
    }
     // 如果弹窗显示则阻止默认行为 上下左右不能操作，避免光标移动位置
    if(isChoose.value){
        if(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.code)){
            isBtnFun();
        }
    }
    // 删除键
    if (event.keyCode === 8) {
        // 等待dom更新
        const timer = setTimeout(() => {
            clearTimeout(timer);
            const s = myTextareaRef.value?.innerHTML.trim();
            if (s === '' || s === '<br>' || s === '<div>&nbsp;</div>') {
                // 拼接随机长度的空格，以刷新dom
                empty();
                selectElement(myTextareaRef.value);
            }
        })
    }
    // 上下键选择@人员
    if ([38, 40].includes(event.keyCode) && isChoose.value) {
        const index = chatUserList.value.findIndex((item, index) =>  chatUserIndex.value === index);
        if(event.keyCode === 38){ // 上
            chatUserIndex.value = index === 0 ? chatUserList.value.length - 1 : index - 1;
        }else if(event.keyCode === 40){ // 下
            chatUserIndex.value = index === chatUserList.value.length - 1 ? 0 : index + 1;
        }
        // 滚动到选中的成员
        nextTick(() => {
            const usersElement = document.getElementById('users');
            if (usersElement) {
                const selectedItem = usersElement.querySelector(`.item:nth-child(${chatUserIndex.value + 1})`);
                if (selectedItem) {
                    selectedItem.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
                }
            }
        });
    }
    // 回车event.tar
    if(event.key === 'Enter'){
        if(!event.shiftKey){
            isBtnFun();
            // 上下键选择@人员
            if(isChoose.value){
                const user = chatUserList.value[chatUserIndex.value];
                onBlur();
                handleUserToSpan(user);
                return;
            }
        }else{
            setIsSend();
            if(!isSend.value){
                // 插入换行符
                isBtnFun();
            }
        }
    }
    const regex = /<(?!img\b)[^>]+>/gi;
    const innerHTML = myTextareaRef.value?.innerHTML.replace(regex, '');
    if(!innerHTML && event.key === 'Enter'){
        isBtnFun();
    }
    const timers = setTimeout(async () => {
        clearTimeout(timers);
        emit('inputVal', innerHTML);
        if(!innerHTML){ // 没有内容才能使用上下键
            if([38, 40].includes(event.keyCode)){
                emit('handlePreNext', { preNext: event.keyCode === 38 ? 'pre' : 'next', topicId: chatDetail.value.id });
            }
        }else{
            if (event.key === 'Enter') { // 回车
                if (event.shiftKey) {
                    // 插入换行符
                    // document.execCommand("insertHTML", false, "<br>");
                    saveCursorPosition();
                } else {
                    const editableDiv = myTextareaRef.value;
                    const innerHTML = ['', '<br>'].includes(editableDiv?.innerHTML || '') ? '' : editableDiv?.innerHTML || '';
					console.log('innerHTML===', myTextareaRef.value?.innerHTML);
                    if(editableDiv && innerHTML){
						function multiReplaceAll(str: string, replacements: { [key: string]: string }): string {
							let result = str;
							for (const [oldStr, newStr] of Object.entries(replacements)) {
								const regex = new RegExp(oldStr, 'g');
								result = result.replace(regex, newStr);
							}
							return result;
						}
						const replacements: { [key: string]: string } = {
							"&nbsp;": "",
							"&lt;": "<",
							"&gt;": ">",
							"&amp;": "&",
						};
						const content = editableDiv?.innerHTML || '';
						const parts = content.split('\n');
                        const processedParts = parts.map(part => `<p>${part ? part : '<br>'}</p>`).join('');
                        const message = multiReplaceAll(processedParts, replacements);
                        const isHave = message.replace(/<p>/g, '').replace(/<\/p>/g, '').trim();
                        const isEmpty = isHave.replace(/<br>/g, '');
                        const isHaveDiv = isHave === '<div></div>';
						console.log('发送消息===', isHave);
						console.log('发送消息===', isEmpty);
						console.log('发送消息===', !isHaveDiv);
                        if(isHave && isEmpty && !isHaveDiv){
                            sendParams.value.content = message;
                            await handleUserToSpan('');
                            // return;
                            editableDiv.textContent = '';
                            isSend.value = false;
                            emit('inputVal', '');
                            if(message.trim()){
                                await handleSend(message);
                            }
                        }
                    }
                }
            }else if([37, 38, 39, 40].includes(event.keyCode)){ // 键盘上下左右也要获取光标位置
                // 给个延时，保证光标在最新位置
                const timer = setTimeout(() => {
                    clearTimeout(timer)
                    saveCursorPosition();
                }, 0);
            }
        }
    }, 0);
}

// 输入内容
const handleInput = async () => {
    // console.log('handleInput===', e);
    saveCursorPosition();
    const { unread, topicId, hasMentioned } = currentGroupInfo.value;
    if (hasMentioned) {
        await getFirstAiteId(topicId);
        currentGroupInfo.value.hasMentioned = false;
    }
    // 如果未读消息大于0，则已读
    if (unread > 0) {
        handleReadList(topicId);
    }

    nextTick(() => {
        sendIptHeight.value = document.getElementById('ipt')?.offsetHeight; // 获取容器高度去计算聊天区的高度
        // handleChatBottom();
        const iptBoxDiv = document.querySelector('.ipt-box'); // 获取父容器
        const editableDiv = myTextareaRef.value; // 获取输入框
        if (!editableDiv || !iptBoxDiv) return;

        // 获取光标位置
        const selection = window.getSelection();
        const range = selection.getRangeAt(0);
        const startOffset = range.startOffset;
        const startContainer = range.startContainer;

        // 获取当前行的文本
        let currentLineText = '';
        if (startContainer.nodeType === 3) {
            currentLineText = startContainer.textContent;
        } else if (startContainer.nodeType === 1) {
            currentLineText = startContainer.innerText;
        }

        // 判断光标前一位是否为 @
        const isAtBeforeCursor = startOffset > 0 && currentLineText[startOffset - 1] === '@';
        isChoose.value = isAtBeforeCursor;
        chatUserIndex.value = isAtBeforeCursor ? 0 : '';

        if (isAtBeforeCursor) {
            // 获取当前行中 @ 符号的位置
            const atIndex = currentLineText.lastIndexOf('@', startOffset - 1);

            if (atIndex !== -1) {
                // 创建一个临时的 span 元素来测量 @ 符号的位置
                const tempSpan = document.createElement('span');
                tempSpan.textContent = currentLineText.slice(atIndex, startOffset);
                tempSpan.style.position = 'absolute';
                tempSpan.style.visibility = 'hidden';
                tempSpan.style.whiteSpace = 'pre-wrap';

                // 将临时 span 元素插入到当前位置
                const tempRange = range.cloneRange();
                tempRange.setStart(startContainer, atIndex);
                tempRange.setEnd(startContainer, startOffset);
                tempRange.insertNode(tempSpan);

                // 获取 @ 符号的坐标
                const rect = tempSpan.getBoundingClientRect();
                const iptBoxRect = iptBoxDiv.getBoundingClientRect();

                // 计算相对于父容器 .ipt-box 的位置
                const topOffset = rect.top - iptBoxRect.top;
                const bottomOffset = iptBoxRect.height - topOffset;

                // 设置选择框的位置
                isChooseLeft.value = rect.left - iptBoxRect.left + rect.width + 5;
                isChooseTop.value = bottomOffset; // 距离父级底部的距离

                // 移除临时 span 元素
                tempSpan.remove();
            }
        }
        setIsSend();
    });
};

// 复制
const onPaste = (e) => {
    const clipboardData = e.clipboardData;
    const items = clipboardData.items;
    // console.log('粘贴====', items);
    // 阻止默认的粘贴行为
    e.preventDefault();
    // 如果剪贴板包含图片
    for (let i = 0; i < items.length; i++) {
        const item = items[i];
        // console.log('复制====', item.type);
        if(item.type?.includes('image')){
            isSend.value = true;
        }
        if (item.type.includes("image")) { // 复制图片
            const file = item.getAsFile();
            const reader = new FileReader();
            reader.readAsDataURL(file); // 转换为Base64
            // 获取图片宽高
            reader.onload = (e) => {
                const img = new Image();
                img.src = e.target.result;
                img.onload = function () {
                    // 原始比例
                    const originalDimensions = { width: img.width, height: img.height };
                    // 缩放比例
                    const resizedDimensions = resizeImageDimensions(originalDimensions.width, originalDimensions.height);
                    insertImageAtCursor(e.target.result, resizedDimensions.width, resizedDimensions.height);  // 插入图片到光标位置
                };
            };
        }else if(item.type.includes("text/plain")){ // 复制其他（如: 文本等）
            const text = clipboardData.getData('text/plain');
            document.execCommand('insertText', false, text);
            saveCursorPosition();
        }
    }
    nextTick(() => {
        handleChatBottom();
        const sendIptElement = myTextareaRef.value;
        if (sendIptElement) {
            sendIptElement.scrollTop = sendIptElement.scrollHeight;
        }
    });
}

// 处理发送消息的类型  0文本  1图片  2文件  3语音  4视频
const handleSendType = (content: string) => {
    let type = 0; // 默认文本
    if( content?.includes('<img')){
        type = 1;
    }else if(content === 'file' || content === 'img'){
        type = 2;
    }else if(content === 'video'){
        type = 4;
    }
    return type;
}

// 发送消息
const handleSend = async (content: string) => {
    try{
        const params: SendParamsEntity = {
            ...sendParams.value,
            type: handleSendType(content),
            topicId: chatDetail.value.id,
        }
        params.extraInfo = params.content ? null : params.extraInfo;
        params.mentionedIds = params.mentionedIds.includes(0) ? [0] : params.mentionedIds;
        // console.log('发送params===', {...params});
        await Api.ApiChatSend(params);
        sendParams.value.mentionedIds = [];
        sendIptHeight.value = document.getElementById('ipt')?.offsetHeight; // 获取容器高度去计算聊天区的高度
        handleChatBottom();
    }catch(err){console.log(err)}
}
// 定义 selectElement 函数，接收一个 Node 类型的元素和一个数字类型的 endOffset
const selectElement = (element: Node, endOffset: number) => {
    // 使用 Vue 的 nextTick 确保在 DOM 更新后执行操作
    nextTick(() => {
        // 获取当前窗口的选区对象，可能为 null
        const selection: Selection | null = window.getSelection();
        if (selection) {
            // 创建一个新的 Range 对象
            const t1: Range = document.createRange();
            try {
                // 设置 Range 的起始位置
                t1.setStart(element, 0);
                // 设置 Range 的结束位置，使用 endOffset 或默认值 0
                t1.setEnd(element, endOffset);
                if (element.firstChild) {
                    // 选择元素第一个子节点的内容
                    t1.selectNodeContents(element.firstChild);
                }
                // 折叠 Range 到起始位置
                t1.collapse();
                // 移除选区中所有已有的 Range
                selection.removeAllRanges();
                // 将新创建的 Range 添加到选区中
                selection.addRange(t1);

                // 检查元素是否有 focus 方法，如果有则调用使其获取焦点
                if (typeof (element as HTMLElement).focus === 'function') {
                    (element as HTMLElement).focus();
                }
            } catch (error) {
                // 捕获并处理可能出现的 Range 操作异常
                console.error('Error setting range:', error);
            }
        }
    });
};

// 清空输入框内容
const empty = () => {
    myTextareaRef.value.innerHTML = "";
    const line = newLine();
    const after = document.createTextNode('\u00A0');
    line.appendChild(after);
    nextTick(() => selectElement(after));
};

// 创建新行
const newLine = () => {
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    const divElement = document.createElement('div');
    const endContainer = range.endContainer;
    const parentElement = endContainer.parentElement;
    if (parentElement.parentElement === myTextareaRef.value) {
        divElement.innerHTML = endContainer.textContent.substring(range.endOffset).trim();
        endContainer.textContent = endContainer.textContent.substring(0, range.endOffset);
        parentElement.insertAdjacentElement('afterend', divElement);
    } else {
        divElement.innerHTML = '';
        myTextareaRef.value.append(divElement);
    }
    return divElement;
};

// 滚动加载
const onScroll = debounce((event) => {
    if(chatList.value.length > 0){
        nextTick(() => {
            const container = chatRef.value;
            // 获取当前的滚动位置
            const currentScrollTop = event.target.scrollTop;
            // 获取容器的滚动高度
            const scrollHeight = container.scrollHeight;
            // 获取容器的可见高度
            const clientHeight = container.clientHeight;

            // 判断滚动方向
            if (currentScrollTop > lastScrollTop.value) {
                scrollDirection.value = 'down';
            } else if (currentScrollTop < lastScrollTop.value) {
                scrollDirection.value = 'up';
            }
            isBottom.value = container.scrollHeight - (container.scrollTop + container.clientHeight) > 200;
            const isUp = scrollDirection.value === 'up';
            if ( container.scrollTop <= 300 && !chatInfo.value.isPreLast && isUp) {
                getRecordList(currentGroupInfo.value.topicId, false);
            }
            const bottomPX = scrollHeight - currentScrollTop - clientHeight;
            if( !currentGroupInfo.value.hasMentioned && bottomPX <= 300 && !chatInfo.value.isNextLast && !isUp){
                getRecordList(currentGroupInfo.value.topicId, false);
            }
            // 更新上一次的滚动位置
            lastScrollTop.value = currentScrollTop;
        })
    }
}, 50)

const mittHandleSubmit = (e) => {
    handleSubmit(e);
}
// 展开、收起
const mittHandleCollapse = (e) => {
    isCollapse.value = e;
}
// 获取客户信息区域的高度
const mittCustomInfoHeight = (e) => {
    customInfoHeight.value = e;
    handleChatBottom();
}
// 删除、归档
const mittHandleChatBtn = (e) => {
    if(e.sendType === 'del'){
        // websocket.send('群聊删除');
    }else if(e.sendType === 'return'){
        chatDetail.value.status = 1;
        // websocket.send('群聊归档');
    }
}

mitt.on('handleSubmit', mittHandleSubmit);
mitt.on('handleCollapse', mittHandleCollapse);
mitt.on('customInfoHeight', mittCustomInfoHeight);
mitt.on('handleChatBtn', mittHandleChatBtn);

// 处理删除、归档、被移除等
const handleChatType = async (value) => {
    const { topicId, btnType, isDetail, unread, hasMentioned, lastMsg: { type, status } } = value;
    console.log('群聊信息===', {...value});
    chatInfo.value = {};
    if(isDetail){
        await getChatDetail(topicId, true);
        if(hasMentioned){ // 如果有@我的消息
            await getFirstAiteId(topicId);
            isAt.value = true;
        }else{
            isAt.value = false;
        }
        chatDetail.value.app = null;
        if(unread > 0){
            // console.log('读取消息======');
            handleReadList(topicId, value.msgType);
        }
        if(chatDetail.value?.status === 1){ // 已归档
            const isHave = chatList.value.some(item => item.type === 31);
            if(!isHave){
                const params = {
                    btnType: 'return',
                    btnTips: '会话已归档',
                }
                chatList.value.push(params);
            }
            isChat.value = false;
            handleChatBottom();
            return;
        }
    }
    if(btnType === 'add'){
        isChat.value = true;
    }
    // 移除群聊 归档都不能发送消息了
    if(['del', 'return', 'remove'].includes(btnType) || type === 33 || status === 1){
        isChat.value = false;
    }else{
        isChat.value = true;
    }
    // 拉人、踢人刷新群用户列表
    if(['add', 'remove'].includes(btnType)){
        getChatUserList(topicId);
        // console.log('拉人踢人===');
    }
    handleChatBottom();
    saveCursorPosition();
}

// 群聊置底
const handleChatBottom = () => {
    nextTick(() => {
        if(chatRef.value){
            chatRef.value.scrollTo(0, chatRef.value.scrollHeight);
        }
    })
}

// 提交-选择成员
const handleSubmit = async ({ userIds, removed, added, addLess }) => {
    console.log('选择成员===', userIds, removed, added, addLess);
    let https = Api.ApiChatUserAdd;
    if(addLess === 'less'){
        https = Api.ApiChatUserDelete;
    }
    try{
        await https(chatDetail.value.id, addLess === 'add' ? added : removed.toString());
    }catch(err){console.log(err);}
    getChatUserList(currentGroupInfo.value.topicId);
}

// 判断当前消息和上一条消息的时间差
const shouldShowTime = (index: number) => {
    if (index === 0) return true; // 第一条消息总是显示时间
    const currentTime = new Date(chatList.value[index].sendTime);
    const previousTime = new Date(chatList.value[index - 1].sendTime);
    const timeDifference = (currentTime - previousTime) / 1000 / 60; // 时间差，单位分钟
    return timeDifference > 2; // 如果时间差超过2分钟，显示时间
}

defineExpose({
    handleSubmit,
    chatDetail,
    getChatDetail,
    currentGroupInfo,
    handleChatType,
    chatList,
    handleReadList
})
</script>
<style lang="scss" scoped>
.arco-skeleton {
    height: calc(100% - 60px);
    padding-top: 120px;
    &.height {
        padding-top: 0px;
    }
    .right-chat {
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: space-between;

        .chat {
            padding: 10px 10px 10px 15px;
            height: calc(100% - 180px);
            overflow: auto;
            display: flex;
            flex-direction: column;
            row-gap: 25px;
            position: relative;
            &.height {
                height: 100%;
            }
            .item {
                :deep(.chat-at-user) {
                    margin: 0 2px;
                }
                &-at {
                    .msg {
                        padding: 5px 10px !important;
                        animation: bg 1s .5s ease-in-out forwards;
                    }
                    :deep(.chat-at-user) {
                        display: inline-block;
                        padding: 1px 6px;
                        background: var(--green);
                        color: white;
                        border-radius: 6px;
                        font-size: 13px;
                        font-weight: bold;
                    }
                }
                @keyframes bg {
                    0% {
                        background-color: #e1e1e3;
                    }
                    50% {
                        background-color: #7dbffa;
                    }
                    100% {
                        background-color: #e1e1e3;
                    }
                }
                .box {
                    display: flex;
                    padding-right: 20%;
                    &-style {
                        padding: 0 !important;
                    }
                    :deep(.arco-avatar) {
                        margin-top: 3px;
                    }
                }
                .time,
                .tips {
                    text-align: center;
                    color: #999;
                    width: 100%;
                    padding: 5px 0;
                }
                .history {
                    position: relative;
                    span {
                        display: inline-block;
                        background: white;
                        width: 120px;
                        padding: 10px;
                        position: relative;
                        z-index: 9;
                    }
                    &::before {
                        content: '';
                        width: 300px;
                        height: 1px;
                        border-bottom: var(--border);
                        position: absolute;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                    }
                }
                .avatar {
                    width: 50px;
                    height: 50px;
                    border-radius: 50%;
                }
                .info {
                    padding-left: 8px;
                    flex: 1;
                    .card {
                        float: initial;
                        display: flex;
                        flex-direction: row-reverse;
                        &.img{
                            box-shadow: initial;
                            padding: 8px;
                            border-radius: 6px;
                            display: inline-block;
                            line-height: 18px;
                            text-align: justify;
                            word-break: break-all;
                            background: #c3e0f8;
                        }
                    }
                    .name {
                        font-weight: bold;
                        font-size: 15px;
                        margin-bottom: 3px;
                        // display: flex;
                        // align-items: center;
                        height: 24px;
                        &-box {
                            display: flex;
                            align-items: center;
                            &.style {
                                flex-direction: row-reverse;
                            }
                        }
                        .creator {
                            display: inline-block;
                            padding: 3px 8px;
                            background: #1677ff;
                            border-radius: 10px;
                            font-size: 11px;
                            margin: 0 8px;
                            color: white;
                        }
                        .email {
                            font-size: 14px;
                            margin-left: 5px;
                            font-weight: normal;
                            display: none;
                        }
                    }
                    .msg {
                        font-size: 14px;
                        background: #e1e1e3;
                        border: var(--border);
                        padding: 8px;
                        border-radius: 6px;
                        display: inline-block;
                        line-height: 18px;
                        text-align: justify;
                        word-break: break-all;
                    }
                    &:hover {
                        .email {
                            display: block;
                        }
                    }
                }
                &-self {
                    .box {
                        justify-content: right;
                        flex-direction: row-reverse;
                        padding-left: 20%;
                        padding-right: 0;
                        &::after {
                            content: "";
                            display: block;
                            clear: both;
                        }
                        .info {
                            text-align: right;
                            padding-right: 8px;
                            .msg {
                                font-size: 14px;
                                border: none;
                                background: #c3e0f8;
                                text-align: left;
                                text-align: justify;
                            }
                            .name {
                                justify-content: end;
                            }
                            .card {
                                float: right;
                            }
                        }
                    }
                }
                .card {
                    &.file {
                        width: 280px;
                        padding: 14px;
                        border-radius: 6px;
                        border: 1px solid #f2f1f1;
                        display: flex;
                        align-items: center;
                        justify-content: space-between;
                        &:hover{
                            cursor: pointer;
                            box-shadow: 0px 3px 10px 4px #f2f1f1;
                        }
                        .left {
                            width: 210px;
                            text-align: left;
                            padding-left: 3px;
                        }
                        .name {
                            color: var(--blue);
                            font-weight: normal !important;
                            cursor: pointer;
                            display: inline-flex;
                            font-size: 14px !important;
                            margin-bottom: 0 !important;
                            height: 22px !important;
                            &>div {
                                max-width: 150px;
                                overflow: hidden;
                                white-space: nowrap;
                                overflow: hidden;
                                text-overflow: ellipsis;
                            }
                            &:hover {
                                text-decoration: underline;
                            }
                        }
                        .size {
                            color: #999;
                            font-size: 12px;
                        }
                        .EachApp {
                            width: 32px;
                        }
                    }
                }
                :deep(.msg) {
                    img {
                        height: 200px;
                        &:not(:last-child) {
                            margin-bottom: 6px;
                        }
                    }
                }
                /* 默认状态，灰色字体 */
                .email-link {
                    color: gray;
                    text-decoration: none; /* 去掉下划线 */
                    transition: color 0.3s, text-decoration 0.3s; /* 平滑过渡效果 */
                }

                /* 鼠标悬停时显示下划线并改变颜色 */
                .email-link:hover {
                    color: #1890ff; /* 悬停时的字体颜色 */
                    text-decoration: underline; /* 悬停时添加下划线 */
                }
            }
        }
        .users {
            box-shadow: 0px 3px 10px 4px #f2f1f1;
            display: inline-block;
            width: 200px;
            max-height: 220px;
            overflow: auto;
            border-radius: 6px;
            background: white;
            position: absolute;
            z-index: 99;
            .item {
                padding: 6px 10px;
                cursor: pointer;
                &:hover {
                    background: #eee;
                }
                .name {
                    margin-left: 10px;
                }
                &-style {
                    background: #eee;
                }
            }
        }

        .ipt {
            padding: 10px;
            &-box {
                position: relative;
                padding: 0;
                background-color: rgb(242, 243, 245);
                padding: 8px 12px;
                width: 100%;
                border-radius: 10px;
                min-height: 30px;
                height: 100%;
                :deep(.chat-at-user) {
                    color: var(--blue);
                    margin: 0 2px;
                }

                :deep(.sendIpt) {
                    margin-top: 4px;
                    font-size: 14px;
                    line-height: 20px;
                    overflow-y: auto;
                    min-width: calc(100% - 150px);
                    max-width: 100%;
                    min-height: 20px; /* 初始高度和工具栏保持一致 */
                    max-height: 140px;
                    height: auto; /* 高度自适应 */
                    float: left;
                    position: relative;
                    scrollbar-width: none;
                    &:focus-visible {
                        outline: initial;
                    }
                    img {
                        display: inline-block !important;
                    }
                }
                .placeholder{
                    &::before{
                        position: absolute;
                        content: '请输入消息...';
                        left: 0;
                        top: 0;
                        color: #999;
                        font-size: 13px;
                    }
                }
                .space{
                    float: right;
                    width: 130px;
                    height: 28px;
                }
                &>.tools {
                    display: flex;
                    align-items: center;
                    justify-content: flex-end;
                    -webkit-user-select: none;
                    -moz-user-select: none;
                    user-select: none;
                    height: 26px; /* 设置工具栏高度 */
                    position: absolute;
                    right: 12px;
                    bottom: 9px;
                }
            }
        }
    }
}

.back-bottom{
	position: fixed;
	right: 30px;
	width: 40px;
	height: 40px;
	display: flex;
	align-items: center;
	justify-content: center;
	bottom: 20px;
	background: white;
	border: 1px solid #eee;
	z-index: 99;
	border-radius: 50%;
	cursor: pointer;
	&:hover{
		background: #eee;
	}
}
</style>
